package net.sf.ivyide.idea;

import com.intellij.openapi.diagnostic.Logger;
import fr.jayasoft.ivy.*;
import fr.jayasoft.ivy.filter.Filter;
import fr.jayasoft.ivy.report.ResolveReport;
import fr.jayasoft.ivy.xml.XmlReportParser;
import net.sf.ivyide.IvyEnvironmentInfo;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URI;
import java.text.ParseException;
import java.util.*;

// Referenced classes of package com.ivyplugin.j2meplugin.module:
//            ProjectStructure, DependencyType, InvalidFileException, IvyModuleSettings

public class ResolvedModule implements Comparable<ResolvedModule> {
    private ModuleId m_moduleId;

    public int compareTo(ResolvedModule right) {
        if (right.equals(this)) {
            return 0;
        } else if (m_internalModules.containsKey(right.m_moduleId)) {
            return -1;
        } else if (right.m_internalModules.containsKey(m_moduleId)) {
            return 1;
        } else {
            return 0;
        }
    }

    public String toString() {
        return m_moduleId.toString();
    }

    public ModuleId getModuleId() {
        return m_moduleId;
    }

    private static final Logger LOGGER = Logger.getInstance(ResolvedModule.class.getName());
    private Map<ModuleId, DependencyType> m_internalModules;
    private Map<ModuleRevisionId, List<Artifact>> m_moduleArtifacts;
    private ResolveReport m_report;

    public Map<ModuleId, DependencyType> getInternalModules() {
        return m_internalModules;
    }

    public ResolveReport getReport() {
        return m_report;
    }

    public Map<ModuleRevisionId, List<Artifact>> getModuleArtifacts() {
        return m_moduleArtifacts;
    }

    public ResolvedModule(IvyProjectSettings settings) {
        this(settings.m_environmentInfo, settings.m_rootModuleDir, settings.m_moduleDependencies);
    }

    public ResolvedModule(IvyEnvironmentInfo environmentInfo, File moduleDir, Map<ModuleId, DependencyType> projectDependencies) {
        if (environmentInfo == null) {
            throw new IllegalArgumentException("no environment");
        } else {
            resolve(environmentInfo.initializeIvy(), environmentInfo, moduleDir, projectDependencies);
        }
    }

    private Artifact[] getDependencyArtifacts(Ivy ivy, URL ivyFileURL, Filter artifactFilter) throws IOException, ParseException {
        m_report = ivy.resolve(ivyFileURL, null, new String[]{
                "*"
        }, ivy.getDefaultCache(), null, true, false, artifactFilter);
        m_moduleId = m_report.getModuleDescriptor().getModuleRevisionId().getModuleId();
        fr.jayasoft.ivy.ModuleId mid = m_report.getModuleDescriptor().getModuleRevisionId().getModuleId();
        XmlReportParser parser = new XmlReportParser();
        Set<Artifact> all = new HashSet<Artifact>();
        String[] confs = m_report.getConfigurations();
        for (String conf : confs) {
            Artifact[] artifacts = parser.getArtifacts(mid, conf, ivy.getDefaultCache());
            all.addAll(Arrays.asList(artifacts));
        }

        return all.toArray(new Artifact[all.size()]);
    }

    private void resolve(Ivy ivy, IvyEnvironmentInfo environmentInfo, File moduleDir, Map<ModuleId, DependencyType> projectDependencies) {
        try {
            URI ivyFileUrl = new File(moduleDir, "ivy.xml").toURI();
            Map<ModuleId, File> modules = environmentInfo.getModules();
            Artifact artifacts[] = getDependencyArtifacts(ivy, ivyFileUrl.toURL(), environmentInfo.getArtifactFilter());
            m_moduleArtifacts = new LinkedHashMap<ModuleRevisionId, List<Artifact>>();
            for (Artifact artifact : artifacts) {
                List<Artifact> moduleArtifacts = m_moduleArtifacts.get(artifact.getModuleRevisionId());
                if (moduleArtifacts == null) {
                    moduleArtifacts = new LinkedList<Artifact>();
                    m_moduleArtifacts.put(artifact.getModuleRevisionId(), moduleArtifacts);
                }
                moduleArtifacts.add(artifact);
            }

            Set<ModuleRevisionId> moduleRevisionIds = m_moduleArtifacts.keySet();
            m_internalModules = new LinkedHashMap<ModuleId, DependencyType>();

            for (ModuleRevisionId moduleRevisionId : moduleRevisionIds) {
                ModuleId moduleId = moduleRevisionId.getModuleId();
                File moduleSourceDescriptor = modules.get(moduleId);
                LOGGER.debug((new StringBuilder()).append(moduleId).append(" ").append(moduleSourceDescriptor).toString());
                if (moduleSourceDescriptor != null) {
                    DependencyType dependencyType = projectDependencies.get(moduleId);
                    if (dependencyType == null)
                        dependencyType = DependencyType.LIBRARY;
                    m_internalModules.put(moduleId, dependencyType);
                }
            }
        } catch (ParseException e) {
            //Should not occur
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void checkResolveReport() {
        ResolveReport report = getReport();
        if (report.hasError()) {
            final StringBuffer buffer = new StringBuffer();
            buffer.append(new StringBuffer("Errors occured during resolution of component " + m_moduleId + "\n"));
            if (report.getUnresolvedDependencies().length > 0) {
                IvyNode[] unresolvedDependencies = report.getUnresolvedDependencies();
                buffer.append("\n");
                buffer.append(unresolvedDependencies.length > 1 ? "Unresolved dependencies:\n" : "Unresolved dependency:\n");
                for (IvyNode unresolvedDependency : unresolvedDependencies) {
                    buffer.append(unresolvedDependency).append("\n");
                }
            }
            buffer.append("\nMake sure the project can be resolved in order to get all depenencies.");
            throw new RuntimeException(buffer.toString());
        }

    }
}